package com.gviiii.pprf.netty.event;

import com.gviiii.pprf.netty.NettyMessage;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component
public class EventEndpoint implements InitializingBean, DisposableBean, ApplicationListener<ContextRefreshedEvent> {

    private static final Logger logger= LoggerFactory.getLogger(EventEndpoint.class);

    protected static Channel channel;

    protected static ChannelHandlerContext chc;

    private Bootstrap bootstrap;

    private NioEventLoopGroup worker;

    private int port;

    public EventEndpoint() {
        init();
    }

    public EventEndpoint(int port) {
        this.port = port;
        init();
    }

    private void init() {
        bootstrap = new Bootstrap();
        worker = new NioEventLoopGroup();
        bootstrap
                .group(worker)
                .channel(NioDatagramChannel.class)
                .handler(new EventChannelInitializer())
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .option(ChannelOption.SO_BROADCAST, true)
                .option(ChannelOption.SO_REUSEADDR,true)
                .option(ChannelOption.SO_RCVBUF, 2048);
    }

    public void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    ChannelFuture future = bootstrap.bind(port).sync();
                    channel = future.channel();
                    channel.closeFuture().await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "EventEndpoint").start();
        logger.info("服务器启动");
    }

    public void stop() {
        if (!worker.isShuttingDown() || !worker.isShutdown())
            worker.shutdownGracefully();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.port = 4004;
    }

    @Override
    public void destroy() throws Exception {
        stop();
    }

    public void send(NettyMessage message){
        if (channel!=null) {
            channel.writeAndFlush(message);
        }
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        start();
    }
}
